from typing import Optional, List

from langchain_core.runnables import RunnableConfig
from pydantic import BaseModel, Field
from ...graph.nodes.base import BaseNodes, tool_node
from ...models.graph import GraphState


class LaunchContainerSchema(BaseModel):
    environment_type: str = Field(
        description="The type of environment to launch (e.g., 'docker', 'sandbox')"
    )
    image_name: str = Field(
        description="The name of the image to use for the environment"
    )
    template: str = Field(
        default=None,
        description="the project's template"
    )
    requires_approval: bool = Field(
        default=True,
        description="Whether this operation requires explicit user approval"
    )


class RunProjectSchema(BaseModel):
    command: str = Field(
        description="The command to run within the project environment"
    )
    working_directory: Optional[str] = Field(
        default=None,
        description="Optional working directory where the command should be executed"
    )
    requires_approval: bool = Field(
        default=False,
        description="Whether this operation requires explicit user approval"
    )


class ExecuteContainerCommandSchema(BaseModel):
    command: str = Field(
        description="The command to execute inside the container"
    )
    requires_approval: bool = Field(
        default=False,
        description="Whether this operation requires explicit user approval"
    )


class ProjectNodes(BaseNodes):
    @tool_node(args_schema=LaunchContainerSchema)
    def launch_container(self, state: GraphState, *, config: Optional[RunnableConfig] = None):
        """
        Description: Launch a container environment for the project. This sets up the runtime environment needed to build, test, or run the project.

        Parameters:
        - environment_type: (required) The type of environment to launch, such as 'docker'.
        - image_name: (required) The name of the image to use for the environment (e.g., 'node:18', 'python:3.9').
        - template: (optional) The name of the project's template. Must be selected from the supported project template list, cannot use template names not in the list. If it doesn't match any template, set it to null.
        - requires_approval: (optional) Whether this operation requires explicit user approval (default: true).

        Usage:
        <launch_container>
        <environment_type>environment type</environment_type>
        <image_name>image name</image_name>
        <template>project template name</template>
        <requires_approval>whether approval is required</requires_approval>
        </launch_container>

        Example:
        <launch_container>
        <environment_type>docker</environment_type>
        <image_name>python:3.9-slim</image_name>
        <template>Flask</template>
        </launch_container>

        Example with null template:
        <launch_container>
        <environment_type>docker</environment_type>
        <image_name>node:16</image_name>
        <template>null</template>
        </launch_container>
        """
        return self.wait_human_feedback()

    @tool_node(args_schema=ExecuteContainerCommandSchema)
    def execute_container_command(self, state: GraphState, *, config: Optional[RunnableConfig] = None):
        """
        Description: Execute a command inside the container. Use this when you need to perform operations within the container environment, such as installing dependencies, configuring the environment, or running system commands.

        Parameters:
        - command: (required) The command to execute inside the container. This should be valid for the container's operating system.
        - requires_approval: (optional) Whether this operation requires explicit user approval (default: false). Set to 'true' for potentially impactful operations like installing/uninstalling packages, system configuration changes, or any commands that could have unintended side effects.

        Usage:
        <execute_container_command>
        <command>Your command here</command>
        <requires_approval>true or false</requires_approval>
        </execute_container_command>

        Example:
        <execute_container_command>
        <command>npm install express</command>
        <requires_approval>true</requires_approval>
        </execute_container_command>
        """
        return self.wait_human_feedback()


    @tool_node(args_schema=RunProjectSchema)
    def run_project(self, state: GraphState, *, config: Optional[RunnableConfig] = None):
        """
        Description: Run a command within the project environment. This executes the specified command in the previously launched container environment.

        Parameters:
        - command: (required) The command to run within the project environment.
        - working_directory: (optional) The working directory where the command should be executed.
        - requires_approval: (optional) Whether this operation requires explicit user approval (default: false).
        - is_gui: (optional) Whether the command is a GUI application (default: false). This is only relevant for commands that launch graphical applications.

        Usage:
        <run_project>
        <command>Your command here</command>
        <working_directory>/optional/path</working_directory>
        <requires_approval>false</requires_approval>
        <is_gui>true or false</is_gui>
        </run_project>

        Example:
        <run_project>
        <command>npm run dev</command>
        <requires_approval>false</requires_approval>
        <is_gui>true</is_gui>
        </run_project>
        """
        return self.wait_human_feedback()
